package com.googlecode.recycled.lang.jse.api;

import com.google.common.base.Objects;
import com.google.common.base.Preconditions;
import com.google.common.base.Predicates;
import com.google.common.base.Splitter;
import com.google.common.collect.Iterables;
import com.google.common.collect.Maps;
import com.googlecode.recycled.lang.assertions.Assert;

import javax.annotation.Nullable;
import java.util.*;

public class Collections {

    public static final String DEFAULT_ENTRY_DELIMITER = ",";
    public static final String DEFAULT_KEYVALUE_DELIMITER = "=";

    protected Collections() {
    }

    public static <T> T firstElementOrNull(Collection<T> collection) {
        if (collection.isEmpty()) {
            return null;
        }
        return collection.iterator().next();
    }

    /**
     * Guava patch proposal rejected by Google guys - see
     * http://groups.google.com/group/guava-discuss/browse_thread/thread/99f0fab8ff50a293 .
     */
    public static <T> List<T> nullToEmpty(@Nullable List<T> list) {
        return Objects.firstNonNull(list, new LinkedList<T>());
    }

    /**
     * Guava patch proposal rejected by Google guys - see
     * http://groups.google.com/group/guava-discuss/browse_thread/thread/99f0fab8ff50a293 .
     */
    public static <T> Set<T> nullToEmpty(@Nullable Set<T> set) {
        return Objects.firstNonNull(set, new HashSet<T>());
    }

    @SuppressWarnings(value = {"unchecked"})
    public static <COL extends Iterable<?>> COL typeSave(Iterable<?> iterable, Class<?> type) {
        Preconditions.checkArgument(
                Iterables.all(iterable, Predicates.instanceOf(type)), "Iterable contains invalid types.");
        return (COL) iterable;
    }

    public static Map<String, String> stringToMap(String string) {
        return stringToMap(string, DEFAULT_KEYVALUE_DELIMITER, DEFAULT_ENTRY_DELIMITER);
    }

    public static Map<String, String> stringToMap(String string, String keyValueDelim, String entryDelim) {
        Splitter entrySplitter = Splitter.on(entryDelim).trimResults();
        Splitter keyValueSplitter = Splitter.on(keyValueDelim).trimResults();

        Map<String, String> map = Maps.newLinkedHashMap();
        Iterable<String> tokens = entrySplitter.split(string);
        for (String token : tokens) {
            String[] items = Iterables.toArray(keyValueSplitter.split(token), String.class);
            Preconditions.checkState(items.length == 2, "Map String not well-formed.");
            map.put(items[0], items[1]);
        }
        return map;
    }

    public static <T, V> Map<T, V> newHashMap(Object... keyValues) {
        if (Assert.notNull(keyValues).length % 2 != 0) {
            throw new IllegalArgumentException("Cannot created map from odd elements.");
        }
        Map map = Maps.newHashMap();
        for (int i = 0; i < keyValues.length; i += 2) {
            map.put(keyValues[i], keyValues[i + 1]);
        }
        return map;
    }

}
